#pragma once

#include "ProtoAdaptor.h"
#include "message.h"

namespace qb {
typedef unsigned long DWORD;

int safe_copy(char* szDestination, size_t isize, const char* szSource);

class SSPROTOAPI CParserTool {
 public:
  static const char* GetString(const ProtoMap& msgmap, const char* name);
  static const char* GetString(const ProtoMessage& msg, const char* name);
  static const char* GetString(const qb::proto::VariantRecord* msg,
                               const char* name);
  static const char* ToGBK(const char* utf8, int len);
  static bool MessageGetTime(const qb::proto::VariantRecord* msg,
                             const std::string& name, time_t& t);

  static bool MessageGetTime(const ProtoMessage& msg, const std::string& name,
                             time_t& t);
  static bool MessageGetInt64toTime(const ProtoMessage& msg,
                                    const std::string& name, time_t& t);
  static bool MessageGetDoubleToFloat(const ProtoMessage& msg,
                                      const std::string& name, float& fvalue);
  static bool MessageGetUint32ToDWORD(const ProtoMessage& msg,
                                      const std::string& name, DWORD& dwValue);
  static bool MessageGetUint64ToDWORD(const ProtoMessage& msg,
                                      const std::string& name, DWORD& dwValue);
  static bool MessageGetUint64ToDouble(const ProtoMessage& msg,
                                       const std::string& name,
                                       double& dwValue);
  static bool MessageGetInt64ToLong(const ProtoMessage& msg,
                                    const std::string& name, long& lValue);

  static bool MessageGetTime(const ProtoMap& msg, const std::string& name,
                             time_t& t);
  static bool MessageGetInt64toTime(const ProtoMap& msg,
                                    const std::string& name, time_t& t);
  static bool MessageGetDoubleToFloat(const ProtoMap& msg,
                                      const std::string& name, float& fvalue);
  static bool MessageGetUint32ToDWORD(const ProtoMap& msg,
                                      const std::string& name, DWORD& dwValue);
  static bool MessageGetUint64ToDWORD(const ProtoMap& msg,
                                      const std::string& name, DWORD& dwValue);
  static bool MessageGetUint64ToDouble(const ProtoMap& msg,
                                       const std::string& name,
                                       double& dwValue);
  static bool MessageGetInt64ToLong(const ProtoMap& msg,
                                    const std::string& name, long& lValue);

  static std::string GetTypebyFuncID(int nFuncID);
  static int GetFuncIDbyType(const std::string& stype);

  static std::string UTF8ToGBK(const std::string& strUTF8);
  static void GetDoubleToString(const char* fieldName, std::string& dest,
                                const ProtoMap& VMap);

 public:
  static bool IsStringEqual(const std::string& str, const char* s);
  static bool VariantRefString(const ProtoValue& vt, std::string& out);
  static void MapRefString(const ProtoMap& vmap, const char* name,
                           std::string& out);
  static bool IsVerbosLogEnable();
  static bool IsCheckEnable();

 private:
  CParserTool() = delete;
  ~CParserTool() = delete;
};

class DecodeMetric {
 public:
  DecodeMetric(double* ptime, const char* buf, int len, int funcid);
  ~DecodeMetric();

 private:
  double* m_ptime;
  //	qb::base::HighResTime m_timer; //syy
  const char* m_buffer;
  int m_length;
  int m_funcid;
};
}  // namespace qb

const uint8_t SSTYPE_MIN = 0;
const uint8_t SSTYPE_UNKNOWN = 0;
const uint8_t SSTYPE_INT8 = 1;
const uint8_t SSTYPE_UINT8 = 2;
const uint8_t SSTYPE_INT16 = 3;
const uint8_t SSTYPE_UINT16 = 4;
const uint8_t SSTYPE_INT32 = 5;
const uint8_t SSTYPE_UINT32 = 6;
const uint8_t SSTYPE_INT64 = 7;
const uint8_t SSTYPE_UINT64 = 8;
const uint8_t SSTYPE_BOOL = 9;
const uint8_t SSTYPE_STRING = 10;
const uint8_t SSTYPE_FLOAT = 11;
const uint8_t SSTYPE_DOUBLE = 12;
const uint8_t SSTYPE_RAW = 13;
const uint8_t SSTYPE_T32 = 14;  // 等同于time_t，精度秒
const uint8_t SSTYPE_T64 = 15;  // 等同于time_t + 毫秒，精度毫秒
const uint8_t SSTYPE_MAX = 15;

#define IFHEAD(key) if (CParserTool::IsStringEqual(vHeaders[cnt], key))

#define GETITEM_STRING(param)                            \
  if (!*sFileBuffer) {                                   \
    ++sFileBuffer;                                       \
    FIELDCOPY(unit.param, sFileBuffer);                  \
    sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1; \
  } else {                                               \
    ++sFileBuffer;                                       \
  }

#define GETITEM_STRING_NULL()                            \
  if (!*sFileBuffer) {                                   \
    ++sFileBuffer;                                       \
    sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1; \
  } else {                                               \
    ++sFileBuffer;                                       \
  }

#define GETITEM_STRING_UTF8(param)                                             \
  if (!*sFileBuffer) {                                                         \
    ++sFileBuffer;                                                             \
    const char* gbkstr = CParserTool::ToGBK(sFileBuffer, strlen(sFileBuffer)); \
    FIELDCOPY(unit.param, gbkstr);                                             \
    sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;                       \
  } else {                                                                     \
    ++sFileBuffer;                                                             \
  }

#define GETITEM_STRING_UTF8_EX(param)                                          \
  if (!*sFileBuffer) {                                                         \
    ++sFileBuffer;                                                             \
    const char* gbkstr = CParserTool::ToGBK(sFileBuffer, strlen(sFileBuffer)); \
    unit.param = gbkstr;                                                       \
    sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;                       \
  } else {                                                                     \
    ++sFileBuffer;                                                             \
  }

#define GETITEM_STDSTRING_UTF8(param)                                          \
  if (!*sFileBuffer) {                                                         \
    ++sFileBuffer;                                                             \
    const char* gbkstr = CParserTool::ToGBK(sFileBuffer, strlen(sFileBuffer)); \
    FIELDCOPY(param, gbkstr);                                                  \
    sFileBuffer = sFileBuffer + strlen(sFileBuffer) + 1;                       \
  } else {                                                                     \
    ++sFileBuffer;                                                             \
  }

#ifndef _MSC_VER
#ifndef MEMCPYS
static void memcpy_s(void* det, size_t detSize, const void* src,
                     size_t srcSize) {
  if (srcSize > detSize || src == NULL || det == NULL) {
    return;
  } else {
    memcpy(det, src, srcSize);
  }
}
#define MEMCPYS
#endif
#endif

#define GETITEM_BUFFER(type, param)                                 \
  if (!*sFileBuffer) {                                              \
    ++sFileBuffer;                                                  \
    memcpy_s(&unit.param, sizeof(type), sFileBuffer, sizeof(type)); \
    sFileBuffer += sizeof(type);                                    \
  } else {                                                          \
    ++sFileBuffer;                                                  \
  }

#define ELSESKIP                                                      \
  else { /*skip buffer because cannot match header name in vHeaders*/ \
    if (*sFileBuffer)                                                 \
      ++sFileBuffer;                                                  \
    else {                                                            \
      --sFileBuffer;                                                  \
      if (*sFileBuffer == SSTYPE_STRING) {                            \
        sFileBuffer += 2;                                             \
        while (*sFileBuffer++)                                        \
          ;                                                           \
      } else if (*sFileBuffer == SSTYPE_FLOAT) {                      \
        sFileBuffer += 6;                                             \
      } else if (*sFileBuffer == SSTYPE_DOUBLE) {                     \
        sFileBuffer += 10;                                            \
      } else if (*sFileBuffer == SSTYPE_INT32) {                      \
        sFileBuffer += 6;                                             \
      }                                                               \
    }                                                                 \
  }
